<html>
<head><meta charset="utf-8"><title>relax priv-in-pub lint for trait impl `where` bounds · t-lang · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/213817-t-lang/index.html">t-lang</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds.html">relax priv-in-pub lint for trait impl `where` bounds</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="222458397"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/213817-t-lang/topic/relax%20priv-in-pub%20lint%20for%20trait%20impl%20%60where%60%20bounds/near/222458397" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jack Wrenn <a href="https://rust-lang.github.io/zulip_archive/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds.html#222458397">(Jan 12 2021 at 16:42)</a>:</h4>
<p>Following <a href="https://www.reddit.com/r/rust/comments/kvc18j/blog_post_rust_gotcha_deriving_copy_and_clone_can/gixozs9/">this thread</a>, I wanted to take the temperature on a possible relaxation of the priv-in-pub lint in a particular situation... (cc <span class="user-mention" data-user-id="125270">@scottmcm</span>)</p>



<a name="222458419"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/213817-t-lang/topic/relax%20priv-in-pub%20lint%20for%20trait%20impl%20%60where%60%20bounds/near/222458419" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jack Wrenn <a href="https://rust-lang.github.io/zulip_archive/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds.html#222458419">(Jan 12 2021 at 16:42)</a>:</h4>
<p>On public trait impls, it's currently an <strong>error</strong> to have a <code>where</code> bound constraining a private type with a trait:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">pub</span><span class="w"> </span><span class="k">trait</span><span class="w"> </span><span class="n">Trait</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
<span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">Type</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>

<span class="k">struct</span> <span class="nc">Priv</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
<span class="k">impl</span><span class="w"> </span><span class="n">Trait</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">Priv</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>

<span class="k">impl</span><span class="w"> </span><span class="n">Trait</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">Type</span><span class="w"></span>
<span class="k">where</span><span class="w"></span>
<span class="w">    </span><span class="n">Priv</span>: <span class="nc">Trait</span><span class="w"> </span><span class="c1">// ERROR</span>
<span class="p">{}</span><span class="w"></span>
</code></pre></div>
<p>...and it's a <strong>warning</strong> to have have a public type bound by a private trait:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">pub</span><span class="w"> </span><span class="k">trait</span><span class="w"> </span><span class="n">Trait</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
<span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">Type</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>

<span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">Pub</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
<span class="k">trait</span><span class="w"> </span><span class="n">Priv</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
<span class="k">impl</span><span class="w"> </span><span class="n">Priv</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">Pub</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>

<span class="k">impl</span><span class="w"> </span><span class="n">Trait</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">Type</span><span class="w"></span>
<span class="k">where</span><span class="w"></span>
<span class="w">    </span><span class="n">Pub</span>: <span class="nc">Priv</span><span class="w"> </span><span class="c1">// WARNING</span>
<span class="p">{}</span><span class="w"></span>
</code></pre></div>
<p><strong>I think these constraints could be relaxed without issue.</strong></p>



<a name="222458517"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/213817-t-lang/topic/relax%20priv-in-pub%20lint%20for%20trait%20impl%20%60where%60%20bounds/near/222458517" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jack Wrenn <a href="https://rust-lang.github.io/zulip_archive/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds.html#222458517">(Jan 12 2021 at 16:43)</a>:</h4>
<p>The primary purpose of the priv-in-pub lints is to prevent programmers from exposing public APIs that are externally unusable. (Secondarily, it provides a definition-site complement to <a href="https://github.com/rust-lang/rfcs/pull/2145">type privacy</a>, which enforces that private types and impls are not unusable outside their visible scope.)</p>
<p>However, private <code>where</code> bounds  on a public trait impl <em>aren't</em> a situation where a public API becomes externally unusable.</p>



<a name="222458560"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/213817-t-lang/topic/relax%20priv-in-pub%20lint%20for%20trait%20impl%20%60where%60%20bounds/near/222458560" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jack Wrenn <a href="https://rust-lang.github.io/zulip_archive/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds.html#222458560">(Jan 12 2021 at 16:43)</a>:</h4>
<p>Such a lint <em>is</em> useful for free functions; e.g.:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">struct</span> <span class="nc">Priv</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">T</span><span class="p">);</span><span class="w"></span>
<span class="k">pub</span><span class="w"> </span><span class="k">trait</span><span class="w"> </span><span class="n">Pub</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
<span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span>: <span class="nc">Pub</span><span class="o">&gt;</span><span class="w"> </span><span class="n">Pub</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">Priv</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>

<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">function</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">()</span><span class="w"></span>
<span class="k">where</span><span class="w"></span>
<span class="w">    </span><span class="n">Priv</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>: <span class="nc">Pub</span><span class="w"> </span><span class="c1">// WARNING</span>
<span class="p">{}</span><span class="w"></span>
</code></pre></div>
<p>...because to call that function in a generic context, you need to 'forward' the <code>where</code> bound to the call-site:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">fn</span> <span class="nf">callsite</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">()</span><span class="w"></span>
<span class="k">where</span><span class="w"></span>
<span class="w">    </span><span class="n">Priv</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>: <span class="nc">Pub</span><span class="w"> </span><span class="c1">// omitting this bound is a compile error</span>
<span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">function</span>::<span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>...which you can only actually do if all elements of the bound are in scope at the call site.</p>



<a name="222458628"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/213817-t-lang/topic/relax%20priv-in-pub%20lint%20for%20trait%20impl%20%60where%60%20bounds/near/222458628" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jack Wrenn <a href="https://rust-lang.github.io/zulip_archive/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds.html#222458628">(Jan 12 2021 at 16:44)</a>:</h4>
<p>But this same reasoning <strong>doesn't</strong> hold for trait impls. To call a method on a public trait impl with private bounds, you don't need to 'forward' those private bounds, you can 'forward' the public trait:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">mod</span> <span class="nn">upstream</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="k">trait</span><span class="w"> </span><span class="n">Trait</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">fn</span> <span class="nf">method</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">Type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">T</span><span class="p">);</span><span class="w"></span>

<span class="w">    </span><span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">Pub</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">T</span><span class="p">);</span><span class="w"></span>
<span class="w">    </span><span class="k">trait</span><span class="w"> </span><span class="n">Priv</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
<span class="w">    </span><span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span>: <span class="nc">Priv</span><span class="o">&gt;</span><span class="w"> </span><span class="n">Priv</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">Pub</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>

<span class="w">    </span><span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="n">Trait</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">Type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="w"></span>
<span class="w">    </span><span class="k">where</span><span class="w"></span>
<span class="w">        </span><span class="n">Pub</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>: <span class="nc">Priv</span><span class="w"> </span><span class="c1">// WARNING</span>
<span class="w">    </span><span class="p">{}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">mod</span> <span class="nn">downstream</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">use</span><span class="w"> </span><span class="k">super</span>::<span class="n">upstream</span>::<span class="o">*</span><span class="p">;</span><span class="w"></span>

<span class="w">    </span><span class="k">fn</span> <span class="nf">function</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">value</span>: <span class="nc">Type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">where</span><span class="w"></span>
<span class="w">        </span><span class="n">Type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>: <span class="nc">Trait</span><span class="w"> </span><span class="c1">// &lt;- no private deets!</span>
<span class="w">    </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="n">value</span><span class="p">.</span><span class="n">method</span><span class="p">();</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>



<a name="222483732"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/213817-t-lang/topic/relax%20priv-in-pub%20lint%20for%20trait%20impl%20%60where%60%20bounds/near/222483732" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> scottmcm <a href="https://rust-lang.github.io/zulip_archive/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds.html#222483732">(Jan 12 2021 at 19:40)</a>:</h4>
<p>I don't think the fn-vs-impl distinction is necessary, since you can already bound functions by unnamable traits using the "make it public in a private module" trick, like I do here: <a href="https://github.com/scottmcm/arraytools/blob/a4a6c1bf31c4c62d7825d6ccdd6d4826d7062e34/src/lib.rs#L398-L460">https://github.com/scottmcm/arraytools/blob/a4a6c1bf31c4c62d7825d6ccdd6d4826d7062e34/src/lib.rs#L398-L460</a></p>



<a name="222484023"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/213817-t-lang/topic/relax%20priv-in-pub%20lint%20for%20trait%20impl%20%60where%60%20bounds/near/222484023" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> scottmcm <a href="https://rust-lang.github.io/zulip_archive/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds.html#222484023">(Jan 12 2021 at 19:43)</a>:</h4>
<p>So it's already possible to write things that can only be called non-generically.  Weakinging the restrictions would just make it easier to write such things.</p>



<a name="222484839"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/213817-t-lang/topic/relax%20priv-in-pub%20lint%20for%20trait%20impl%20%60where%60%20bounds/near/222484839" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Matthew Jasper <a href="https://rust-lang.github.io/zulip_archive/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds.html#222484839">(Jan 12 2021 at 19:49)</a>:</h4>
<p>Does <a href="https://rust-lang.github.io/rfcs/2145-type-privacy.html">https://rust-lang.github.io/rfcs/2145-type-privacy.html</a> address this?</p>



<a name="222505316"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/213817-t-lang/topic/relax%20priv-in-pub%20lint%20for%20trait%20impl%20%60where%60%20bounds/near/222505316" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jack Wrenn <a href="https://rust-lang.github.io/zulip_archive/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds.html#222505316">(Jan 12 2021 at 22:31)</a>:</h4>
<p><span class="user-mention silent" data-user-id="125270">scottmcm</span> <a href="#narrow/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds/near/222484023">said</a>:</p>
<blockquote>
<p>So it's already possible to write things that can only be called non-generically.  Weakinging the restrictions would just make it easier to write such things.</p>
</blockquote>
<p>Yep! I only draw the distinction because the priv-in-pub lint exists to <em>discourage</em> (but not make impossible) situations like that, because of a community value judgement that those situations are undesirable — but <code>where</code> bounds on trait impls <em>don't</em> give way to the same undesirable scenario. Turning of the lint in this particular case should be extra uncontroversial.</p>



<a name="222505866"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/213817-t-lang/topic/relax%20priv-in-pub%20lint%20for%20trait%20impl%20%60where%60%20bounds/near/222505866" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jack Wrenn <a href="https://rust-lang.github.io/zulip_archive/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds.html#222505866">(Jan 12 2021 at 22:36)</a>:</h4>
<p><span class="user-mention silent" data-user-id="116118">Matthew Jasper</span> <a href="#narrow/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds/near/222484839">said</a>:</p>
<blockquote>
<p>Does <a href="https://rust-lang.github.io/rfcs/2145-type-privacy.html">https://rust-lang.github.io/rfcs/2145-type-privacy.html</a> address this?</p>
</blockquote>
<p>Yes, that RFC/mechanism sets the stage for weakening many errors of the pub-in-priv lint into warnings (or muting them altogether), without affecting the soundness of the visibility system. It's just a matter of <em>actually</em> weakening/muting the lint now. (cc <span class="user-mention" data-user-id="123856">@Vadim Petrochenkov</span>)</p>



<a name="222510358"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/213817-t-lang/topic/relax%20priv-in-pub%20lint%20for%20trait%20impl%20%60where%60%20bounds/near/222510358" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Vadim Petrochenkov <a href="https://rust-lang.github.io/zulip_archive/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds.html#222510358">(Jan 12 2021 at 23:21)</a>:</h4>
<p>Yeah, this just needs an implementation.</p>



<a name="222510384"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/213817-t-lang/topic/relax%20priv-in-pub%20lint%20for%20trait%20impl%20%60where%60%20bounds/near/222510384" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Vadim Petrochenkov <a href="https://rust-lang.github.io/zulip_archive/stream/213817-t-lang/topic/relax.20priv-in-pub.20lint.20for.20trait.20impl.20.60where.60.20bounds.html#222510384">(Jan 12 2021 at 23:21)</a>:</h4>
<p>By a very pedantic person.</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>